#region Copyright & License
/* Tyng.Data
 * Copyright (c) 2007, Paul Tyng, All rights reserved.
 * Code licensed under the BSD License:
 * http://www.opensource.org/licenses/bsd-license.php
 * Downloaded from: http://code.google.com/p/tyngdata/
*/
#endregion

using System;
using System.Data;

namespace Tyng.Data
{
	/// <summary>
	/// Abstract IDataRecord that uses an array of Field instances to support the interfaces methods
	/// </summary>
	public abstract class FieldDataRecord : IDataRecord
	{
		private Field[] _fields;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="fields">Array of fields for this record</param>
		protected FieldDataRecord(Field[] fields)
		{
			if(fields == null)
				throw new ArgumentNullException("fields");

			_fields = fields;
		}

		/// <summary>
		/// Gets the value for a specified column
		/// </summary>
		/// <param name="i">The column ordinal</param>
		/// <returns>Typed value</returns>
		protected abstract object GetValue(int i);

		/// <summary>
		/// GetBytes is not supported by this abstract class, but can be implemented in a subtype
		/// </summary>
		/// <param name="i">Column ordinal</param>
		/// <param name="fieldOffset">Offset within the field to begin copying from</param>
		/// <param name="buffer">Data buffer</param>
		/// <param name="bufferOffset">Offset in the buffer to begin copying to</param>
		/// <param name="length">Length of the data to copy</param>
		/// <returns>Number of bytes copied</returns>
		protected virtual long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
		{
            object o = GetValue(i);
            byte[] bytes = o as byte[];

            if (bytes == null) throw new InvalidCastException();

            if (buffer == null) return bytes.LongLength;

            long data = bytes.LongLength - fieldOffset;

            data = Math.Min(length, data);

            Array.Copy(bytes, fieldOffset, buffer, bufferOffset, data);

            return data;
		}

		/// <summary>
		/// GetData is not supported by this abstract class but can be implemented in a subtype
		/// </summary>
		/// <param name="i">Column ordinal</param>
		/// <returns>IDataReader for column data</returns>
		protected virtual IDataReader GetData(int i)
		{
			throw new NotSupportedException("GetData not supported");
		}

		private int GetOrdinal(string name)
		{
			for(int i = 0; i < _fields.Length; i++)
				if(_fields[i].Name == name)
					return i;

			return -1;
		}

		private string GetString(int i)
		{
			return GetValue(i).ToString();
		}		

		#region IDataRecord Members

		object IDataRecord.GetValue(int i)
		{
			return GetValue(i);
		}

		long IDataRecord.GetBytes(int i, long fieldOffset, byte[] buffer, int bufferOffset, int length)
		{
			return GetBytes(i, fieldOffset, buffer, bufferOffset, length);
		}

		IDataReader IDataRecord.GetData(int i)
		{
			return GetData(i);
		}

		bool IDataRecord.IsDBNull(int i)
		{
			if(DBNull.Value.Equals(GetValue(i)))
				return true;

			return false;
		}
		
		int IDataRecord.GetValues(object[] values)
		{
			int i;

			for(i = 0; i < values.Length && i < _fields.Length; i++)
				values[i] = GetValue(i);

			return i;
		}

		int IDataRecord.GetOrdinal(string name)
		{
			return GetOrdinal(name);
		}

		int IDataRecord.GetInt32(int i)
		{
			return Convert.ToInt32(GetValue(i));
		}

		object IDataRecord.this[string name]
		{
			get
			{
				return GetValue(GetOrdinal(name));
			}
		}

		object IDataRecord.this[int i]
		{
			get
			{
				return GetValue(i);
			}
		}
		
		byte IDataRecord.GetByte(int i)
		{
			return Convert.ToByte(GetValue(i));
		}

		Type IDataRecord.GetFieldType(int i)
		{
			return _fields[i].DataType;
		}

		decimal IDataRecord.GetDecimal(int i)
		{
			return Convert.ToDecimal(GetValue(i));
		}

		string IDataRecord.GetName(int i)
		{
			return _fields[i].Name;
		}

		int IDataRecord.FieldCount
		{
			get
			{
				return _fields.Length;
			}
		}

		long IDataRecord.GetInt64(int i)
		{
			return Convert.ToInt64(GetValue(i));
		}

		double IDataRecord.GetDouble(int i)
		{
			return Convert.ToDouble(GetValue(i));
		}

		bool IDataRecord.GetBoolean(int i)
		{
			return Convert.ToBoolean(GetValue(i));
		}

		Guid IDataRecord.GetGuid(int i)
		{
			return new Guid(GetString(i));
		}

		DateTime IDataRecord.GetDateTime(int i)
		{
			return Convert.ToDateTime(GetValue(i));
		}

		string IDataRecord.GetDataTypeName(int i)
		{
			return _fields[i].DataTypeName;
		}

		float IDataRecord.GetFloat(int i)
		{
			return Convert.ToSingle(GetValue(i));
		}

		long IDataRecord.GetChars(int i, long fieldOffset, char[] buffer, int bufferOffset, int length)
		{
            string val = GetString(i);

            if (buffer == null) return val.Length;

			char[] data = val.ToCharArray((int) fieldOffset, length);

			Array.Copy(data, 0, buffer, bufferOffset, length);

			return Math.Min(length, val.Length - fieldOffset);
		}

		string IDataRecord.GetString(int i)
		{
			return GetString(i);
		}

		char IDataRecord.GetChar(int i)
		{
			return Convert.ToChar(GetValue(i));
		}

		short IDataRecord.GetInt16(int i)
		{
			return Convert.ToInt16(GetValue(i));
		}

		#endregion
	}
}
